<?php
namespace frame;
/**
 * FramePHP内置的Dispatcher类
 * 完成URL解析、路由和调度
 */
class Dispatcher {
    /**
     * URL映射到控制器
     * @access public
     * @return void
     */
    static public function dispatch(){
        //1.读取url配置信息的变量,定义常量
        $varPath        =   C('VAR_PATHINFO');//兼容模式PATHINFO获取变量例如(s) ?s=/module/action/id/1
        $varAddon       =   C('VAR_ADDON');// 默认的插件控制器命名空间变量 
        $varModule      =   C('VAR_MODULE');//默认模块获取变量m
        $varController  =   C('VAR_CONTROLLER');//默认控制器获取变量c
        $varAction      =   C('VAR_ACTION');// 默认操作获取变量a
        $urlCase        =   C('URL_CASE_INSENSITIVE');//表示URL区分大小写，默认false true则表示不区分大小写
        $depr           =   C('URL_PATHINFO_DEPR');//PATHINFO模式下，各参数之间的分割符号/
        define('MODULE_PATHINFO_DEPR',  $depr);
        // URL常量(strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签,C('URL_REQUEST_URI')默认为REQUEST_URI)
        define('__SELF__',strip_tags($_SERVER[C('URL_REQUEST_URI')]));

        //2.兼容模式和cli模式下生成pathinfo
        self::createServerPathInfo($varPath);

        //3.对$_SERVER['PATH_INFO']处理，再进行定义
        if(empty($_SERVER['PATH_INFO'])) {
            $_SERVER['PATH_INFO'] = '';
            define('__INFO__','');
            define('__EXT__','');
        }else{ 
            define('__INFO__',trim($_SERVER['PATH_INFO'],'/'));
            $_SERVER['PATH_INFO'] = __INFO__;
            // URL后缀
            define('__EXT__', strtolower(pathinfo($_SERVER['PATH_INFO'],PATHINFO_EXTENSION)));

            //对module模块进行处理，生成get['m']
            if(!C('URL_ROUTER_ON') || !Route::check()){
                if (__INFO__ && C('MULTI_MODULE')){ 
                    // 获取模块名,规定所返回的数组元素的数目。
                    $paths      =   explode($depr,__INFO__,2);
                    $allowList  =   C('MODULE_ALLOW_LIST'); // 允许的模块列表
                    $module     =   preg_replace('/\.' .__EXT__ . '$/i', '',$paths[0]);
                    //不存在允许的模块，不区分大小写的in_array实现,设置get[m]
                    if( empty($allowList) || (is_array($allowList) && in_array_case($module, $allowList))){
                        //$_GET['m'] = $module
                        $_GET[$varModule]       =   $module;
                        $_SERVER['PATH_INFO']   =   isset($paths[1])?$paths[1]:'';
                    }
                }
            }             
        }
   
        //4.获取模块名称，如果模块存在，加载模块配置文件
        define('MODULE_NAME',self::getModule($varModule));
        // 检测模块是否存在
        if(MODULE_NAME && !in_array_case(MODULE_NAME,C('MODULE_DENY_LIST')) 
            && is_dir(APP_PATH.MODULE_NAME)){
            //每个单词转换成小写
            define('MODULE_PATH', APP_PATH.strtolower(MODULE_NAME).'/');
           	 // 定义当前模块的模版缓存路径
            C('CACHE_PATH',CACHE_PATH.strtolower(MODULE_NAME).'/');
            // 定义当前模块的日志目录
	        C('LOG_PATH',  realpath(LOG_PATH).'/'.MODULE_NAME.'/');
	        // 加载模块配置文件
            if(is_file(MODULE_PATH.'conf/config'.CONF_EXT)){
            	C(load_config(MODULE_PATH.'conf/config'.CONF_EXT));
            }
            // 加载模块函数文件
            if(is_file(MODULE_PATH.'common/function.php')){
            	include MODULE_PATH.'common/function.php';
            }
        	$urlCase  =   C('URL_CASE_INSENSITIVE');
            // 加载模块的扩展配置文件(common/conf和common/common)
            load_ext_file(MODULE_PATH);
        }else{
        	//没有模块抛出异常
            E(L('_MODULE_NOT_EXIST_').':'.MODULE_NAME);
        }

        //5.为了定义当前应用地址,为了生成__APP__常量
        if(!defined('__APP__')){
	        $urlMode        =   C('URL_MODEL');
	        if($urlMode == URL_COMPAT ){// 兼容模式判断
	            define('PHP_FILE',_PHP_FILE_.'?'.$varPath.'=');
	        }elseif($urlMode == URL_REWRITE ) {
                //_PHP_FILE_代表/index.php
	            $url    =   in_array(dirname(_PHP_FILE_),array('/','\\')) ? '' : $url;
	            define('PHP_FILE',$url);
	        }else{
	            define('PHP_FILE',_PHP_FILE_);
	        }
	        // 当前应用地址
	        define('__APP__',strip_tags(PHP_FILE));
	    }

	     //6.生成模块URL地址常量
        $moduleName    =   defined('MODULE_ALIAS')? MODULE_ALIAS : MODULE_NAME;   
        define('__MODULE__',(defined('BIND_MODULE') || !C('MULTI_MODULE'))? __APP__ : __APP__.'/'.($urlCase ? strtolower($moduleName) : $moduleName));
       
        if('' != $_SERVER['PATH_INFO'] && (!C('URL_ROUTER_ON') ||  !Route::check()) ){  
            //7.通过paths生成get的controller,action
            if(!defined('BIND_CONTROLLER')) {// 获取控制器
                if(C('CONTROLLER_LEVEL')>1){// 控制器层次
                    $_GET[$varController]   =   implode('/',array_slice($paths,0,C('CONTROLLER_LEVEL')));
                    $paths  =   array_slice($paths, C('CONTROLLER_LEVEL'));
                }else{
                    $_GET[$varController]   =   array_shift($paths);
                }
            }
            //获取action
            if(!defined('BIND_ACTION')){
                $_GET[$varAction]  =   array_shift($paths);
            }
        }
        // 获取控制器的命名空间（路径）,有问题？
        define('CONTROLLER_PATH',   self::getSpace($varAddon,$urlCase));

        //8.获取控制器和操作方法的名称和地址
        define('CONTROLLER_NAME',   defined('BIND_CONTROLLER')? BIND_CONTROLLER : self::getController($varController,$urlCase));
        define('ACTION_NAME',       defined('BIND_ACTION')? BIND_ACTION : self::getAction($varAction,$urlCase));
        // 当前控制器的UR地址
        $controllerName    =   defined('CONTROLLER_ALIAS')? CONTROLLER_ALIAS : CONTROLLER_NAME;
        define('__CONTROLLER__',__MODULE__.$depr.(defined('BIND_CONTROLLER')? '': ( $urlCase ? parse_name($controllerName) : $controllerName )) );

        // 当前操作的URL地址
        define('__ACTION__',__CONTROLLER__.$depr.(defined('ACTION_ALIAS') ? ACTION_ALIAS : ACTION_NAME));
   
        //保证$_REQUEST正常取值
        $_REQUEST = array_merge($_POST,$_GET,$_COOKIE); // -- 加了$_COOKIE.  保证哦..
    }

    /**
     * 兼容模式和cli模式下生成pathinfo
     */
      static private function createServerPathInfo($varPath){
        if(isset($_GET[$varPath])) { 
            // 判断URL里面是否有兼容模式参数
            $_SERVER['PATH_INFO'] = $_GET[$varPath];
            unset($_GET[$varPath]);
        }elseif(IS_CLI){ 
            // CLI模式下 php index.php module/controller/action/params/...
            /* [root@DELL113 lee]# /usr/local/php/bin/php test.php a b c d
            接收到5个参数Array
            (
                [0] => test.php
                [1] => a
                [2] => b
                [3] => c
                [4] => d
            )*/
            $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';
        }
    }


    /**
     * 获得控制器的命名空间路径 便于插件机制访问
     */
    static private function getSpace($varAddon,$urlCase) {
        //$space  =   !empty($_GET[$var])?strip_tags($_GET[$var]):'';
        return '';
    }



     /**
     * 获得实际的模块名称
     */
    static private function getModule($varModule) {
        $module   = (!empty($_GET[$varModule])?$_GET[$varModule]:C('DEFAULT_MODULE'));
        //已获取到module,需要去掉get['m']
        unset($_GET[$varModule]);
        /*
        模块映射
        如果不希望用户直接访问某个模块，可以设置模块映射（对后台的保护会比较实用）。
        'URL_MODULE_MAP'    =>    array('test'=>'admin'),
        注意：设置了模块映射后，原来的Admin模块将不能访问，只能访问test模块。
        */
        if($maps = C('URL_MODULE_MAP')) {
            if(isset($maps[strtolower($module)])) {
                // 记录当前别名
                define('MODULE_ALIAS',strtolower($module));
                // 获取实际的模块名
                //return   ucfirst($maps[MODULE_ALIAS]);
                return   $maps[MODULE_ALIAS];
            }elseif(array_search(strtolower($module),$maps)){
                // 禁止访问原始模块
                return   '';
            }
        }
        //return strip_tags(ucfirst($module));
        return strip_tags($module);//strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签。
    }

        /**
     * 获得实际的控制器名称
     */
    static private function getController($varController,$urlCase) {
        $controller = (!empty($_GET[$varController])? $_GET[$varController]:C('DEFAULT_CONTROLLER'));
        unset($_GET[$varController]);
        if($urlCase) {
            // URL地址不区分大小写
            // 智能识别方式 user_type 识别到 UserTypeController 控制器
            //$controller = parse_name($controller,1);
        }
        return strip_tags(ucfirst($controller));
    }


    /**
     * 获得实际的操作名称
     */
    static private function getAction($varAction,$urlCase) {
        $action   = !empty($_POST[$varAction]) ?  $_POST[$varAction] : 
        (!empty($_GET[$varAction])  ? $_GET[$varAction]:C('DEFAULT_ACTION'));
        unset($_POST[$varAction],$_GET[$varAction]);
        return strip_tags($urlCase? strtolower($action) : $action);
    }


}